UPDATE: This document was for Ubuntu 8.04 (Hardy). See this revised document for Ubuntu 10.04 (Lucid). Or see this document for Debian 7.1 Wheezy.
We have a Windows network (Windows server and Windows clients) at work, with an Ubuntu server that has an external IP address. I wanted to allow certain users to be able to connect via a VPN. I also wanted to allow them to do it without any special software on their machines. Our Windows Server had a private IP address and only one network card, so the basic RRAS solution was not going to work for me.
I read a lot of online documentation and "how-to"s trying to get things working. I have listed some of these sites at the bottom of this document. However, I found myself referencing Jacco de Leeuw's site more than most.
I made several changes to the procedures I found online to bring them up to my current standards or to work with my particular network. Below is the step-by-step I went through to set up a "VPN server" that would work with the native Windows client.
Running on Ubuntu Server 8.04 which is also serving as our proxy server, so it has an external IP address and an internal IP address on two different NICs. It is assumed that you run the following commands as root when needed and that you are smart enough to know when that might be.
Windows VPN clients use either PPTP or IPSec L2TP. In this guide, we'll use IPSec L2TP. We set things up first with Pre-shared Keys (PSK) since it's easier to test, then we step through using certificates with the default Windows Server Certificate Authority (CA). I also wanted to authenticate users off of their domain password and only if they were in a particular group.
Note: In this guide, the external IP of the machine is listed as 12.34.56.78. The gateway IP is listed as 12.34.56.1. The internal IP of the VPN server (since it has a NIC on both the inside and the outside) is 192.168.1.1 in this example. Change these for your set up.
This will allow the Windows clients to create an IPSec SA between itself and the VPN server.
nano /etc/apt/sources.list
Uncomment the universe and the security universe lines (total of 4 lines)
apt-get update
apt-get install openswan
No, do not enable Opportunistic Encryption
No, do not create a RSA public/private keypair
cp /etc/ipsec.d/examples/l2tp-psk.conf /etc/ipsec.d/l2tp-psk.conf
nano /etc/ipsec.d/l2tp-psk.conf
Set left=12.34.56.78
[should be set to your external IP address on the machine users will connect to]
leftnexthop=12.34.56.1
[set this to your external gateway]
nano /etc/ipsec.conf
Add: include /etc/ipsec.d/l2tp-psk.conf
Also, for Windows Vista to work properly, we need to tell it which private subnets are allowed, and which are not. In our example, since our company's internal subnet is 192.168.1.0/24, we disallow that (at the end of the line).
virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!192.168.1.0/24
nano /etc/ipsec.secrets
Add: 12.34.56.78 %any: "yourSharedPSK!"
/etc/init.d/ipsec restart
At this point, your VPN server should be listening on port 500/udp and 4500/udp for connections. You can check this using netstat -antu
.
This will check to see if the IPSec side of things is working properly.
You'll need to allow udp/500 and udp/4500 to your external interface through the firewall on your INPUT chain. I also added protocol 50. How this looks depends on your firewall implementation, but my iptables filter rules look like this:
-A INPUT -p 50 -j ACCEPT
-A INPUT -p udp -d 12.34.56.78 --dport 500 -j ACCEPT
-A INPUT -p udp -d 12.34.56.78 --dport 4500 -j ACCEPT
On a Windows XP client, we set things up for a quick test:
Control Panel > Network Connections > File > New connection...
Select Connect to the network at my workplace
Select Virtual Private Network connection
Company Name: Your Company
Select Do not dial the initial connection
Host name or IP address: 12.34.56.78
Properties > Security > IPSec Settings > Check Use pre-shared key for authentication
Pre-shared key: yourSharedPSK!
Properties > Network > Type of VPN: L2TP IPSec VPN
Whether you want to allow split tunneling is up to you: Properties > Networking > TCP/IP > Properties > Advanced... > General > Uncheck Use default gateway on remote network
Now, monitor /var/log/auth.log (perhaps with tail -f /var/log/auth.log
) and connect with the Windows client.
In the end, the connection will fail, but you should see connection attempts on the VPN server with a STATE_QUICK_R2: IPsec SA established
. This means the IPSec side of things is working with the pre-shared key.
Since Windows default client is more than just IPSec, it uses L2TP inside of an IPSec SA, we need a daemon to handle that.
apt-get install xl2tpd
This package is in the universe repositories currently.
Modify /etc/xl2tpd/xl2tpd.conf
so it includes at least the following:
[global]
ipsec saref = yes
listen-addr = 12.34.56.78
[lns default]
ip range = 192.168.1.10-192.168.1.20
local ip = 192.168.1.1
;require chap = yes
refuse chap = yes
refuse pap = yes
require authentication = yes
ppp debug = yes
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes
The IP range specified above should be set to IP addresses of your internal network which can be given to your VPN clients. Don't worry much that we are refusing CHAP and PAP methods, because we will require MS-CHAP v2 next.
cp /etc/ppp/options /etc/ppp/options.xl2tpd
nano /etc/ppp/options.xl2tpd
Change noauth
to auth
.
Set name l2tpd
. You can really set it to something other than l2tpd, but you have to match it in the next file.
Set mru 1280
and mtu 1280
. I had some weird trouble with Vista's Remote Desktop not working over the VPN if these were left at their defaults of 1500. 1280 is chosen because that is the minimum required if the IPv6 protocol is to work as well (although that is not covered in this document).
/etc/ppp/chap-secrets
#client server secret IP addresses username l2tpd "password" 192.168.1.1/24 l2tpd username "password" 192.168.1.1/24
Match the l2tpd with the name in the previous file. You can use this to test your CHAP authentication if you want... but you'd have to temporarily change the refuse chap = yes
line above. I put it here just so you know how to test it if you want.
At this point, you need to add an extra rule to your firewall. Some of the sites I reference urge you to be security-minded here because if you open up this port to the whole world, then anyone may try to authenticate without IPSec. Basically, you want to allow connections to udp/1701, but they'd better be connected via IPSec. My filter rule looks like the following:
-A INPUT -m policy --dir in --pol ipsec -p udp --dport 1701 -j ACCEPT
This will allow L2TP traffic to connect to us ONLY if it shows up in an IPSec packet. The best information I've found about how IPSec (NETKEY) interacts with the iptables firewall was found in this post by Nigel Metheringham.
I found there was a little bug with the install of xl2tpd. It expects a file to be there which isn't always there. I had to add a few lines in /etc/init.d/xl2tpd
after it includes the default settings:
if !([ -f /var/run/xl2tpd/l2tp-control ]); then
mkdir -p /var/run/xl2tpd
touch /var/run/xl2tpd/l2tp-control
fi
The last firewall modification we need to make for xl2tpd (which we could probably get more picky if you wanted). When an L2TP connection is made, it creates a ppp# interface on the VPN server, so we need to allow it to talk to the other interfaces.
-A FORWARD -i ppp+ -p all -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
I wanted to have the authentication based off of the Windows AD rather than some /etc/ppp/chap-secrets file.
apt-get install smbclient
apt-get install winbind
Make sure /etc/resolv.conf
points to your DNS servers that have your AD information. Add an A and PTR record for the machine if you don't already have that.
apt-get install krb5-user
(includes krb5-config)
Kerberos servers for your realm: windowsserver.example.local
Administrative servers for your realm: windowsserver.example.local
/etc/samba/smb.conf
(if not specifically listed, I just left the defaults):
workgroup = EXAMPLE
interfaces = eth0 lo
bind interfaces only = true
security = ADS
realm = EXAMPLE.LOCAL
password server = windowsserver.example.local
idmap uid = 10000-20000
idmap gid = 10000-20000
/etc/krb5.conf
(I believe this file is case-sensitive. I only list the lines here that I modified from the default.)
default-realm = EXAMPLE.LOCAL [REALMS] EXAMPLE.LOCAL = { kdc = windowsserver.example.local admin_server = windowsserver.example.local }Run:
/etc/init.d/winbind restart
Note that the clocks of the Windows server and the VPN server must be within 5 minutes of each other for the next commands:
net ads join -U Administrator
This joins the Ubuntu server to the Windows domain. On one machine, I had to make sure that the FQDN was listed in /etc/hosts
before it let me join the domain.
net ads testjoin
This line tests to see if the VPN server was properly joined to the AD domain.
/etc/ppp/options.xl2tpd
and add:
require-mschap-v2
# We can enable MPPE for additional encryption, but all this should be coming over IPSec anyway
#require-mppe-128
ms-dns 192.168.1.3
ms-dns 192.168.1.4
# The following lines let the authentication occur against the Windows domain, and require the user to be a member of the 'VPN Users' group on the 'EXAMPLE' domain.
plugin winbind.so
ntlm_auth-helper '/usr/bin/ntlm_auth --helper-protocol=ntlm-server-1 --require-membership-of="EXAMPLE\\VPN Users"'
This assumes that you already have Certificate Services set up on your Windows Server. I don't go into a lot of detail here.
openssl req -new -out vpn.example.com.pem
Enter PEM pass phrase:
Country: US
State: State
Locality: City Name
Organization: Your Company Name
OU:
CN: vpn.example.com
E-mail:
Challenge password:
Optional company name:
mv vpn.example.com.pem /etc/ssl/private
chmod 640 /etc/ssl/private/vpn.example.com.pem
Load up your Certification Authority on Windows. Right-click on the server, All Tasks > Submit new request... and give it the vpn.example.com.pem file you created.
Choose Pending Requests. Right-click the request, All Tasks > Issue
In Issued Certificates, Open the certificate
Details tab > Copy to File...
Choose DER encoded binary X.509 (.cer)
Export the certificate for the CA as well (not the private key!) using the Certificate snap-in of mmc
.
Copy both to your VPN server.
openssl x509 -inform DER -in windowsserver.example.local.cer -outform PEM -out windowsserver.example.local.pem
This just converts the DER encoded file to a .PEM file.
cp windowsserver.example.local.pem /etc/ipsec.d/cacerts
IPSec needs to know the public key of the CA for verification purposes.
openssl x509 -inform DER -in vpn.example.com.cer -outform PEM -out vpn.example.com.pem
cp vpn.example.com.pem /etc/ipsec.d/certs
Takes the generated certificate for our VPN server and lets openswan (IPSec) use it as needed.
cp /etc/ipsec.d/examples/l2tp-cert.conf /etc/ipsec.d/l2tp-cert.conf
/etc/ipsec.conf
Replace l2tp-psk.conf
with l2tp-cert.conf
.
Also, for Windows Vista to work properly, we need to tell it which private subnets are allowed, and which are not. In our example, since our company's internal subnet is 192.168.1.0/24, we disallow that (at the end of the line).
virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!192.168.1.0/24
/etc/ipsec.d/l2tp-cert.conf
. Vista seems to like or need the leftid setting.
left=12.34.56.78
leftnexthop=12.34.56.1
leftid=@vpn.example.com
leftcert=/etc/ipsec.d/certs/vpn.example.com.pem
openssl req -new -keyout vpn.example.com.pem
PEM passphrase: passphraseToAccessFile
This tells openssl to spit out our private key into a file.
mv vpn.example.com.pem /etc/ipsec.d/private/vpn.example.com.pem
Move this private key to a place where IPSec (openswan) can have access to it.
We need to modify/etc/ipsec.secrets
to make sure it can use the private key associated with our certificate:
Comment out the pre-shared key we put in there earlier and add the line (including the colon):
: RSA vpn.example.com.pem "passphraseToAccessFile"
/etc/init.d/ipsec restart
First off, we need to get a certificate for the Windows machine. With Windows XP Professional attached to a domain, this is fairly straight-forward and I believe you can even push the certificates to the machines. It may go something like this for you:
Start > Run > mmc
> File > Add/Remove Snap-in... > Add... > Certificates > Select Computer account
> Local computer > Close > OK
Highlight Certificates > Personal, Right-click > All Tasks > Request New Certificate...
However, I was dealing with a bunch of Windows XP Home machines, unfortunately, so I had to go about things in a different way. I had to download Windows Server 2003 SP1 Administration Tools Pack (Adminpak) KB304718.
From there, one could take certreq.exe
, certutil.exe
, certcli.dll
, and certadm.dll
to a different machine.
Create req.inf:
[NewRequest]
Subject="CN=foo.example.com,C=US"
KeyLength=2048
MachineKeySet=TRUE
Silent=TRUE
certreq.exe -new req.inf Request.pem
Request.pem
file to the CA, submit the request and issue the certificate. View the certificate details and Copy to File...certutil.exe -encode Issued.cer Issued.pem
certutil.exe -addstore "root" windowsserver.example.local.cer
certreq.exe -accept Issued.pem
This puts the Windows CA in the Trusted Root folder and accepts (into the Personal folder) the issued certificate that we requested earlier.
With Windows XP, you must run these commands as an administrative user. Windows Vista can use the same commands and needs to be running as an administrator as well. However, certutil.exe, etc. may need to be a different version between XP and Vista.
You should be able to connect to the VPN without using a PSK now!
This setup should work even if the client is behind a NAT (using NAT-T on udp/4500). One caveat I've noticed however is that the client cannot be initially on the same subnet as your organization's internal IP range. Meaning, if your company is using 192.168.1.0/24 and your user happens to be using the same IP range at home, he or she will not be able to connect. For one, this is because Windows will not know how to route the packets. Is a particular packet to 192.168.1.100 meant to go over the VPN or stay local?
Another caveat that I've noticed is that I don't think two computers can connect to the server from behind the same NAT.
This is obviously a very brief setup guide and I don't go into lots of details on how it all works. You can read some of the sources at the bottom for more information. However, if you do see a better way to do things, let me know. My e-mail address can be deduced from the very bottom of the document.
Hope things work for you!
http://www.jacco2.dds.nl/networking/openswan-l2tp.html
http://support.real-time.com/open-source/ipsec/index.html
http://koeppe-net.de/l2tp-howto.txt
http://www.members.optushome.com.au/~wskwok/poptop_ads_howto_1.htm
http://www.isaserver.org/img/upl/vpnkitbeta2/xpvpnclient.htm
http://www.jacco2.dds.nl/networking/certutil.html
http://lists.openswan.org/pipermail/users/2005-August/006101.html
-----
I hope this helps someone. Let me know if there are errors above and I'll update this document.
-W Gillespie (wgillespie, es2eng.com)
Last updated: 2011-08-19